/*
 * Copyright (c) 2015. For Intelligent Group.
 */

package com.intelligent.ispc.foundation.io;

import org.apache.commons.io.IOUtils;

import java.io.*;
import java.util.Iterator;
import java.util.zip.GZIPInputStream;

/**
 * Created by Peter.Li on 2015/10/28.
 */
public class TextFileLineIterator implements Iterable<String>, Closeable {
    /**
     * The file being read.
     */
    private final BufferedReader in;

    /**
     * Set to true once the input closes, either manually or automatically it won't close "in"
     * more than once.
     */
    private boolean closed = false;

    /**
     * Create the object using a filename.
     *
     * @param filenameToRead the filename to read
     * @throws java.io.IOException error opening the file to read
     */
    public TextFileLineIterator(final String filenameToRead) throws IOException {
        this(new File(filenameToRead));
    }

    /**
     * Create the object using a file.
     *
     * @param fileToRead the filename to read
     * @throws IOException error opening the file to read
     */
    public TextFileLineIterator(final File fileToRead) throws IOException {
        this(fileToRead.toString().toLowerCase().endsWith(".gz")
                ? new GZIPInputStream(new FileInputStream(fileToRead))
                : new FileInputStream(fileToRead));
    }

    /**
     * Create the object using an InputStream.
     *
     * @param stream the stream for the file to read
     * @throws java.io.IOException error opening the file to read
     */
    public TextFileLineIterator(final InputStream stream) {
        in = new BufferedReader(new InputStreamReader(stream));
    }

    /**
     * This is the one method of the Iterable interface.
     *
     * @return the iterator
     */
    public Iterator<String> iterator() {
        return new TextFileIterator();
    }

    /**
     * For either manual or automatic closing.
     *
     * @throws IOException won't get thrown but included for the interface
     */
    public void close() throws IOException {
        if (!closed) {
            IOUtils.closeQuietly(in);
            closed = true;
        }
    }

    /**
     * This non-static member class is the iterator implementation.
     */
    class TextFileIterator implements Iterator<String> {

        /**
         * Return value of next call to next().
         */
        private String nextline;

        /**
         * The constructor for the iterator.
         */
        public TextFileIterator() {
            // Open the file and read and remember the first line.
            // We peek ahead like this for the benefit of hasNext().
            try {
                nextline = in.readLine();
            } catch (IOException e) {
                throw new IllegalArgumentException(e);
            }
        }

        /**
         * If the next line is non-null, then we have a next line.
         *
         * @return if we have a next line
         */
        public boolean hasNext() {
            return nextline != null;
        }

        /**
         * Return the next line, but first read the line that follows it.
         *
         * @return the next line
         */
        public String next() {
            try {
                final String result = nextline;

                // If we haven't reached EOF yet
                if (nextline != null) {
                    nextline = in.readLine(); // Read another line
                    if (nextline == null) {
                        close();
                    }
                }

                // Return the line we read last time through.
                return result;
            } catch (IOException e) {
                throw new IllegalArgumentException(e);
            }
        }

        /**
         * Remove not supported.
         * The file is read-only; we don't allow lines to be removed.
         */
        public void remove() {
            throw new UnsupportedOperationException();
        }
    }
}
